﻿using System;
using System.Text;
using System.Net;
using System.IO;
using System.Net.Security;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;

public class HttpTools
{

    private WebProxy Proxy = null;

    public const string ContentTypeForm = "application/x-www-form-urlencoded";
    public const string ContentTypeJson = "application/json;charset=UTF-8";
    public const string ContentTypeFormData = "multipart/form-data";
    public const string ContentTypeImageTif = "image/tiff";
    public const string ContentTypeImageJpg = "image/jpeg";
    public const string ContentTypeImagePng = "image/png";
    public const string ContentTypeImageGif = "image/gif";
    public const string ContentTypeHtml = "text/html";
    public const string ContentTypeHtmlGBK = "text/html; charset=gbk";
    public const string ContentTypeHtmlUTF8 = "text/html; charset=utf-8";
    public const string ContentTypeXmlUTF8 = "text/xml; charset=utf-8";
    public const string ContentTypeText = "text/plain";
    public const string ContentTypeTextUTF8 = "text/plain; charset=utf-8";
    public const string ContentTypeTextGBK = "text/plain; charset=gbk";

    public const string UserAgentAll = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36";

    public bool AllowAutoRedirect=true;
    public string ContentType;
    public string UserAgent;

    private string redirectUrl = null;
    public string RedirectUrl { get {return redirectUrl;}}

    public CookieContainer cookies=new CookieContainer();
    public WebHeaderCollection Headers = new WebHeaderCollection();


    public int Timeout = 0;

    public void SetWebProxy(string url)
    {
        if (string.IsNullOrEmpty(url))
            Proxy = null;
        else
            Proxy = new WebProxy(url);
    }


    public void SetDefaultProxy()
    {
        Proxy = (WebProxy)WebRequest.GetSystemWebProxy();
    }

    public void ClearProxy()
    {
        Proxy = null;
    }

    public string HttpPost(string url, string postData, Encoding encoding = null)
    {

        byte[] dataArray = Encoding.Default.GetBytes(postData);
        //创建请求
        HttpWebRequest request = HttpWebRequest.CreateHttp(url);
        request.Headers.Add(Headers);
        if (url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            request.ProtocolVersion = HttpVersion.Version10;
        }
        if (!String.IsNullOrEmpty(ContentType))
            request.ContentType = ContentType;
        if (!String.IsNullOrEmpty(UserAgent))
            request.UserAgent = UserAgent;

        if (Proxy != null) request.Proxy = Proxy;
        request.Method = "POST";
        if (Timeout > 0) request.Timeout = Timeout;
        
        request.AllowAutoRedirect = AllowAutoRedirect;
        request.ContentLength = dataArray.Length;
        request.CookieContainer = cookies;
       
        //创建输入流
        Stream dataStream = null;
        try
        {
            dataStream = request.GetRequestStream();
        }
        catch (Exception ex)
        {
            throw new Exception("HttpError:" + ex.Message);
        }
        //发送请求
        dataStream.Write(dataArray, 0, dataArray.Length);
        dataStream.Close();
        //读取返回消息
        try
        {
            int count = request.MaximumAutomaticRedirections;
            while (count > 0)
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.Moved)
                {
                    redirectUrl = Encoding.Default.GetString(Encoding.GetEncoding("ISO-8859-1").GetBytes(response.GetResponseHeader("Location")));
                    request = CreateGetRequest(redirectUrl);   //301 302重定向之后会转成get
                    count--;
                    response.Close();
                }
                else
                {
                    StreamReader reader = new StreamReader(response.GetResponseStream(), encoding ?? Encoding.Default);
                    string res = reader.ReadToEnd();
                    reader.Close();
                    return res;
                }
                CookieCollection cookieheader = request.CookieContainer.GetCookies(new Uri(url));
                cookies.Add(cookieheader);
            }
            throw new Exception("HttpError:达到最大重定向次数限制!");

        }
        catch (Exception ex)
        {
            throw new Exception("HttpError:" + ex.Message); //连接服务器失败
        }
    }

    private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
    {
        return true; //总是接受  
    }


    public HttpWebRequest CreateGetRequest(string url)
    {
        HttpWebRequest request = HttpWebRequest.CreateHttp(url);
        request.Headers.Add(Headers);
        if (url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            request.ProtocolVersion = HttpVersion.Version10;
        }
        if (!String.IsNullOrEmpty(ContentType))
            request.ContentType = ContentType;
        if (!String.IsNullOrEmpty(UserAgent))
            request.UserAgent = UserAgent;

        if (Proxy != null) request.Proxy = Proxy;
        request.Method = "GET";
        if (Timeout > 0) request.Timeout = Timeout;
        request.AllowAutoRedirect = AllowAutoRedirect;
        request.CookieContainer = cookies;
        request.ContentLength = 0;
        
        return request;
    }

    public static Encoding getEncodingFromStr(String str)
    {
        int i = str.IndexOf("charset=");
        if(i>=0)
        {
            i+=8;
            int l = str.IndexOf(';', i );
            if (l >0) 
               return Encoding.GetEncoding(str.Substring(i, l-i));
            return Encoding.GetEncoding(str.Substring(i));
        }
        return Encoding.Default;
    }

    public string HttpGet(string url, Encoding encoding = null)
    {
        //创建请求
        HttpWebRequest request = CreateGetRequest(url);
        //读取返回消息
        try
        {
            int count = request.MaximumAutomaticRedirections;
            while (count > 0)
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.Moved)
                {
                    String redirectUrl = Encoding.Default.GetString(Encoding.GetEncoding("ISO-8859-1").GetBytes(response.GetResponseHeader("Location")));
                    request = CreateGetRequest(redirectUrl);
                    count--;
                    response.Close();
                }
                else
                {
                    if (encoding == null)
                        encoding = getEncodingFromStr(response.ContentType);
                    StreamReader reader = new StreamReader(response.GetResponseStream(), encoding);
                    string res = reader.ReadToEnd();
                    reader.Close();
                    response.Close();
                    return res;
                }
                CookieCollection cookieheader = request.CookieContainer.GetCookies(new Uri(url));
                cookies.Add(cookieheader);
            }
            throw new Exception("HttpError:达到最大重定向次数限制!");
        }
        catch (Exception ex)
        {
            throw new Exception("HttpError:" + ex.Message);
        }

    }

    public static string sizeFormat(long size)
    {
        if (size == 0) return "";
        else if (size >= 0x40000000) //>=1G
        {
            return ((double)size / 0x100000).ToString("F2") + " GB";
        }
        else if (size >= 0x100000)  //>=1M
        {
            return ((double)size / 0x100000).ToString("F2") + " MB";
        }
        else if (size >= 1024)  //>=1k
        {
            return ((double)size / 1024).ToString("F2") + " KB";
        }
        else
            return size.ToString() + "B";
    }

    public class DownloadStatus
    {
        public long TotalSize;
        public string TotalSizeText { get { return sizeFormat(TotalSize); } }
        public long CurSize;
        public string CurSizeText { get { return sizeFormat(CurSize); } }
        public bool StopSignal;
        public bool DeleteWhenStop;

        public double GetProgress()
        {
            if (TotalSize > 0)
            {
                return 100d*CurSize / TotalSize;
            }
            return 0d;
        }

        public string GetProgressText()
        {
            if(TotalSize>0)
            {
                return (CurSize*100/TotalSize).ToString()+"%";
            }
            return "";
        }
        
    }

    public void HttpGetFile(string filename, string url, DownloadStatus status)
    {

        HttpWebRequest request = CreateGetRequest(url);
        FileStream file=null;
        //保存文件
        try
        {
            int count = request.MaximumAutomaticRedirections;
            while (count>0)
            {
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                if (response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.Moved)
                {
                    String redirectUrl = Encoding.Default.GetString(Encoding.GetEncoding("ISO-8859-1").GetBytes(response.GetResponseHeader("Location")));
                    request = CreateGetRequest(redirectUrl);
                    count--;
                    response.Close();
                }
                else
                {
                    if(status!=null)
                    {
                        status.TotalSize = response.ContentLength;
                        status.CurSize = 0;
                    }
                    var reader = response.GetResponseStream();
                    byte[] buffer = new byte[0x10000];
                    file = File.Create(filename,0x100000);
                    int size = reader.Read(buffer, 0, buffer.Length);
                    while (size > 0 )
                    {
                        if(status!=null&&status.StopSignal)
                        {
                            file.Close();
                            reader.Close();
                            response.Close();
                            if (status.DeleteWhenStop)
                                File.Delete(filename);
                            throw new Exception("UserMsg:Get stop signal, abort!");
                        }
                        status.CurSize += size;
                        file.Write(buffer, 0, size);                        
                        size = reader.Read(buffer, 0, buffer.Length);
                    }
                    file.Close();
                    reader.Close();
                    count = 0;
                    response.Close();
                }
                CookieCollection cookieheader = request.CookieContainer.GetCookies(new Uri(url));
                cookies.Add(cookieheader);
            }
        }
        catch (Exception ex)
        {
            throw new Exception("HttpError:" + ex.Message);
        }

    }

    public bool get(string url)
    {
        //创建请求
        HttpWebRequest request = HttpWebRequest.CreateHttp(url);
        request.Headers.Add(Headers);
        if (url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            request.ProtocolVersion = HttpVersion.Version10;
        }
        if (!String.IsNullOrEmpty(ContentType))
            request.ContentType = ContentType;
        if (!String.IsNullOrEmpty(UserAgent))
            request.UserAgent = UserAgent;
        request.CookieContainer = cookies;
        if (Proxy != null) request.Proxy = Proxy;
        request.Method = "GET";
        request.ContentLength = 0;
        if (Timeout > 0) request.Timeout = Timeout;
        try
        {
            request.GetResponse().Close();
            CookieCollection cookieheader = request.CookieContainer.GetCookies(new Uri(url));
            cookies.Add(cookieheader);
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return false;
        }

    }


}
